#include "LecteurPhraseAvecArbre.h"

#include <stdlib.h>
#include <iostream>
using namespace std;

////////////////////////////////////////////////////////////////////////////////
LecteurPhraseAvecArbre::LecteurPhraseAvecArbre(string nomFich) :
	ls(nomFich), ts() {
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::analyse() {
	arbre=programme();
	cout << "Syntaxe correcte." << endl;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::programme() {
	// <programme> ::= debut <seq_inst> fin FIN_FICHIER

	sauterSymCour("debut");
	Noeud* si = seqInst();
	sauterSymCour("fin");
	testerSymCour("<FINDEFICHIER>");
	return si;
}


/********************************* STRUCTURES *********************************/
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::affectation() {
// <affectation> ::= <variable> = <expression>
                                                                                                                cout<<"affectation"<<endl;
	testerSymCour("<VARIABLE>");
	Noeud* var = ts.chercheAjoute(ls.getSymCour());
	ls.suivant();
	sauterSymCour("=");
	Noeud* exp = expression();
	return new NoeudAffectation(var,exp);
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::expression() {
// <expression> ::= <facteur> { <opBinaire> <facteur> }
                                                                                                                cout<<"expression"<<endl;
	Noeud* OpG = facteur();
	while (ls.getSymCour()=="+" || ls.getSymCour()=="-" ||
		ls.getSymCour()=="*" || ls.getSymCour()=="/") {
		Symbole operateur = opBinaire(); // on stocke le symbole de l'opérateur
		Noeud* OpD=facteur(); // lecture de l'operande droit
		OpG = new NoeudOperateurBinaire(operateur,OpG,OpD); // const. du noeud
	}
	return OpG;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::facteur() {
// <facteur> ::= <entier>  |  <variable>  |  - <facteur>  |  ( <expression> )

                                                                                                                cout<<"facteur"<<endl;
	Noeud* fact=NULL;

	if (ls.getSymCour()=="<VARIABLE>" || ls.getSymCour()=="<ENTIER>") {
		fact=ts.chercheAjoute(ls.getSymCour());
		ls.suivant();
	} else if (ls.getSymCour()=="-") {
		ls.suivant();
		// on représente le moins unaire (- facteur) par une soustractin binaire (0 - facteur)
		fact = new NoeudOperateurBinaire(Symbole("-"), ts.chercheAjoute(Symbole("0")), facteur());
	} else if (ls.getSymCour()=="(") {
		ls.suivant();
		fact=expression();
		sauterSymCour(")");
	} else
		erreur("<facteur>");
	return fact;
}
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::relation()
//<relation> ::= <expression> { <opRel> <expression> } 
{                                                                                                                cout<<"relation"<<endl;
    Noeud* OpG=expression();
    while (ls.getSymCour()=="==" || ls.getSymCour()=="!="
        ||  ls.getSymCour()=="<" || ls.getSymCour()=="<="
        || ls.getSymCour()==">" || ls.getSymCour()==">=")
        {
        Symbole operateur = opRel();                    
        Noeud* OpD=expression();
	OpG= new NoeudOperateurBinaire(operateur,OpG,OpD);
	}    
    return OpG;
 } 
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::expBool()
//<expBool> ::= <termeBool> { <opOu> <termeBool> }
{                                                                                                                cout<<"expBool"<<endl;
    Noeud* OpG= termeBool();
    while(ls.getSymCour()=="ou")
    {
         Symbole s=ls.getSymCour();
         sauterSymCour("et");
         Noeud* OpD=relation();
         OpG=new NoeudOperateurBinaire(s,OpG,OpD);
    }
    
     return OpG;
}


////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre:: termeBool()
//<temrmeBool>::=<relation> {<opEt> <relation>}
{
    Noeud* OpG=relation();
     while(ls.getSymCour()=="et")
    {
         Symbole s=ls.getSymCour();
         sauterSymCour("et");
         Noeud* OpD=relation();
       
       
        OpG=new NoeudOperateurBinaire(s,OpG,OpD);
    }
    
     return OpG;
}
/******************************* INSTRUCTIONS *********************************/
////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::seqInst() {
	// <seqInst> ::= <inst> ; { <inst> ; }

	NoeudSeqInst* si = new NoeudSeqInst();
	do {
		si->ajouteInstruction(inst());
		sauterSymCour(";");
	} while (ls.getSymCour()=="<VARIABLE>" ||ls.getSymCour()=="si"
                ||ls.getSymCour()=="tantque" ||ls.getSymCour()=="repeter"
                ||ls.getSymCour()=="lire" ||ls.getSymCour()=="ecrire"
                ||ls.getSymCour()=="pour");
	// tant que le symbole courant est un debut possible d'instruction...
	return si;
}

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::inst() {
// <inst> ::= <affectation> | <instSi> | <instTq> | <instRepeter>

    Noeud* inst;
    if (ls.getSymCour()=="<VARIABLE>")
        inst=affectation();        
    else if(ls.getSymCour()=="si" )
    {
         inst=instSi();
    }
    else if(ls.getSymCour()=="tantque")
    {
        inst=instTq();
    }
    else if (ls.getSymCour()=="repeter")
    {
       inst=instRepeter();
    }
    else if (ls.getSymCour()=="lire")
    {
       inst=instLire();
    }
    else if (ls.getSymCour()=="ecrire")
    {
       inst=instEcrire();
    }
    else if (ls.getSymCour()=="pour")
    {
        inst=instPour();
    }
    else
	erreur("<inst>");
    
    return inst;

}

////////////////////////////////////////////////////////////////////////////////_________________________________________dois marcher
Noeud* LecteurPhraseAvecArbre::instSi(){
//      <instSi> ::= si ( <expBool> ) <seqInst> { sinonsi ( <expBool> ) <seqInst> } [ sinon <seqInst> ] finsi
    
    sauterSymCour("si");
    sauterSymCour("(");
    Noeud* cond=expBool();
    sauterSymCour(")");
    sauterSymCour("alors");
    sauterSymCour("{");
    Noeud* seq=seqInst();
    sauterSymCour("}");
    NoeudInstSi* si = new NoeudInstSi(cond,seq);
    

    
    while(ls.getSymCour()=="sinonsi")  // utiliser ajouteSinonSi() dans la boucle
    {
        ls.suivant();
        sauterSymCour("(");
        Noeud* cond=expBool();
        sauterSymCour(")");
        sauterSymCour("alors");
        sauterSymCour("{");
        Noeud* seq=seqInst();
        sauterSymCour("}");
        si->ajoute(cond, seq);
    }
    
   if(ls.getSymCour()=="sinon"){    //utiliser ajouteSinon 
    ls.suivant();
    sauterSymCour("{");
    Noeud* seq=seqInst();
    sauterSymCour("}");
    si->ajoute(NULL, seqInst());
   }

    return si;

}

////////////////////////////////////////////////////////////////////////////////
 Noeud* LecteurPhraseAvecArbre::instTq(){
 //      <instTq> ::= tantque ( <expBool> ) <seqInst> fintantque
     //NoeudInstTq* tq = new NoeudInstTq();
   
        sauterSymCour("tantque");
        sauterSymCour("(");
        //expBool();
        Noeud* expBooleen=expBool();
        sauterSymCour(")");
        sauterSymCour("{");
        //seqInst();
        Noeud* seqInstruction= seqInst();
        sauterSymCour("}");
        sauterSymCour("fintantque");
        NoeudInstTq* tq = new NoeudInstTq(expBooleen,seqInstruction);
        return tq;
        
 }
 
  ////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instRepeter(){
//      <instRepeter> ::= repeter <seqInst> jusqua ( <expBool> )
     
     sauterSymCour("repeter");
     sauterSymCour("{");
     //seqInst();
     Noeud* seqInstruction=seqInst();
     sauterSymCour("}");
     sauterSymCour("jusqua");
     sauterSymCour("(");
     //expBool();
     Noeud* expBooleen= expBool();
     sauterSymCour(")");
     
     NoeudInstRepeter* rpt = new NoeudInstRepeter(seqInstruction,expBooleen);
     return rpt;
     
 }

////////////////////////////////////////////////////////////////////////////////
Noeud* LecteurPhraseAvecArbre::instLire(){
  //  <instLire> ::= lire ( <variable> )
    
    sauterSymCour("lire");
    sauterSymCour("(");
    testerSymCour("<VARIABLE>");
    Noeud* var = ts.chercheAjoute(ls.getSymCour());
    //ts.chercheAjoute(ls.getSymCour());
    ls.suivant();
    sauterSymCour(")");
    NoeudInstLire* lire= new NoeudInstLire(var);
    return lire;
}

////////////////////////////////////////////////////////////////////////////////_____________________à faire
Noeud* LecteurPhraseAvecArbre::instEcrire(){
  //  <instEcrire> ::= ecrire ( <expression> | <chaine> )
    
    Noeud* ecrit=NULL;
    sauterSymCour("ecrire");
    sauterSymCour("("); 
    if(ls.getSymCour()=="<CHAINE>")
    {	
        Noeud* ecrit =ts.chercheAjoute(ls.getSymCour());
        //ts.chercheAjoute(ls.getSymCour());
	ls.suivant();
    }
    else{ //expression();  
        ecrit=expression();
    }
    sauterSymCour(")");  
    NoeudInstEcrire* ecrire= new NoeudInstEcrire(ecrit);
    return ecrire;
    
}
  ////////////////////////////////////////////////////////////////////////////////
 Noeud* LecteurPhraseAvecArbre::instPour(){
//      <instPour> : pour (<affectation>;<expBool>; <affectation>) faire { <seqInst> } 
     
     sauterSymCour("pour");
     sauterSymCour("(");
     Noeud* affect1=affectation();
     sauterSymCour(";");
     Noeud* expBooleen=expBool();
     sauterSymCour(";");
     Noeud* affect2=affectation();
     sauterSymCour(")");
     sauterSymCour("faire");
     sauterSymCour("{");
     Noeud* inst=seqInst();
     sauterSymCour("}");
     
     NoeudInstPour* pour= new NoeudInstPour(affect1,expBooleen,affect2,inst);
     return pour;

  }
/******************************** OPERATEURS **********************************/
////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opBool()
// <opBool> ::= et | ou
{
	if (ls.getSymCour()=="et" || ls.getSymCour()=="ou")
        {	
            Symbole* symb= new Symbole(ls.getSymCour());
            ls.suivant();
            return *symb;
        }
	else
        {
		erreur("<opBool>");
        }
}
////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opEt()
// <opEt> ::= et 
{
    if (ls.getSymCour()=="et")
    {
        Symbole* symb= new Symbole(ls.getSymCour());
            ls.suivant();
            return *symb;
    }
    else
        {
		erreur("<opEt>");
        }
}
////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opOu()
// <opOu> ::= ou
{
        if (ls.getSymCour()=="ou")
    {
        Symbole* symb= new Symbole(ls.getSymCour());
            ls.suivant();
            return *symb;
    }
    else
        {
		erreur("<opOu>");
        }
}

////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opRel()
//<opRel> ::= == | != | < | <= | > | >=
{
    if (ls.getSymCour()=="==" || ls.getSymCour()=="!="
        ||  ls.getSymCour()=="<" || ls.getSymCour()=="<="
        || ls.getSymCour()==">" || ls.getSymCour()==">=" )
        {	
                Symbole* symb= new Symbole(ls.getSymCour());
                ls.suivant();
                return *symb;
        }
	else
        {
		erreur("<opRel>");
        }
}

////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opUnaire()
// <opUnaire> ::= - | non
{
    if (ls.getSymCour()=="-" || ls.getSymCour()=="non")
    {
        Symbole* symb= new Symbole(ls.getSymCour());
            ls.suivant();
            return *symb;
    }
    else
        {
		erreur("<opUnaire>");
        }
}


////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opAdd() {
// <opAdd> ::= + | -

	if (ls.getSymCour()=="+" || ls.getSymCour()=="-")
        {
		Symbole* symb= new Symbole(ls.getSymCour());
            ls.suivant();
            return *symb;
        }
	else
		erreur("<opAdd>");
}

////////////////////////////////////////////////////////////////////////////////
Symbole LecteurPhraseAvecArbre::opMult() {
// <opMult> ::= * | /

	if (ls.getSymCour()=="*" || ls.getSymCour()=="/")
        {
            Symbole* symb= new Symbole(ls.getSymCour());
            ls.suivant();
            return *symb;
        }
		
	else
		erreur("<opMult>");
}

////////////////////////////////////////////////////////////////////////////////
////void LecteurPhraseAvecArbre::opBinaire() { <-- avant
//
//// <opBinaire> ::= + | - | *  | /
//
//	if (ls.getSymCour()=="+" || ls.getSymCour()=="-" || 
//		ls.getSymCour()=="*" || ls.getSymCour()=="/" )
//		ls.suivant();
//	else
//		erreur("<opBinaire>");
//}
//
//
//
////////////////////////////////////////////////////////////////////////////////

Symbole LecteurPhraseAvecArbre::opBinaire() { 
// <opBinaire> ::= + | - | *  | /

	if (ls.getSymCour()=="+" || ls.getSymCour()=="-" || 
		ls.getSymCour()=="*" || ls.getSymCour()=="/" )
        {
            Symbole* symb= new Symbole(ls.getSymCour());
            ls.suivant();
            return *symb;
        }
	else
		erreur("<opBinaire>");

}
/********************************** AUTRES ************************************/
////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::testerSymCour(string ch) {
	if (ls.getSymCour() != ch) {
		cout << endl << "-------- Erreur ligne " << ls.getLigne()
				<< " - Colonne " << ls.getColonne() << endl << "   Attendu : "
				<< ch << endl << "   Trouve  : " << ls.getSymCour() << endl
				<< endl;
		exit(0); // plus tard, on levera une exception
	}
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::sauterSymCour(string ch) {
	testerSymCour(ch);
	ls.suivant();
}

////////////////////////////////////////////////////////////////////////////////
void LecteurPhraseAvecArbre::erreur(string mess) {
	cout << endl << "-------- Erreur ligne " << ls.getLigne() << " - Colonne "
			<< ls.getColonne() << endl << "   Attendu : " << mess << endl
			<< "   Trouve  : " << ls.getSymCour() << endl << endl;
	exit(0); // plus tard, on levera une exception
}
